From 9017f91ebbf3c633cf03bb2f0ba9a1dea5160649 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 5 Jun 2006 14:28:39 -0600 Subject: [PATCH] [IA64] more cleanup Clean-up: fw_emul.c created. More definitions moved to mm.c process.c is lighter and renamed to faults.c Signed-off-by: Tristan Gingold --- xen/arch/ia64/xen/Makefile | 3 +- xen/arch/ia64/xen/dom_fw.c | 330 ---------------- xen/arch/ia64/xen/domain.c | 108 +++++- xen/arch/ia64/xen/{process.c => faults.c} | 291 +------------- xen/arch/ia64/xen/fw_emul.c | 453 ++++++++++++++++++++++ xen/arch/ia64/xen/hypercall.c | 52 +++ xen/arch/ia64/xen/mm.c | 337 ++++++++++++++++ xen/arch/ia64/xen/xenmisc.c | 351 ----------------- xen/include/asm-ia64/domain.h | 3 + 9 files changed, 946 insertions(+), 982 deletions(-) rename xen/arch/ia64/xen/{process.c => faults.c} (67%) create mode 100644 xen/arch/ia64/xen/fw_emul.c diff --git a/xen/arch/ia64/xen/Makefile b/xen/arch/ia64/xen/Makefile index 4b2bb1ce3d..adda2ec873 100644 --- a/xen/arch/ia64/xen/Makefile +++ b/xen/arch/ia64/xen/Makefile @@ -3,6 +3,7 @@ obj-y += dom0_ops.o obj-y += domain.o obj-y += dom_fw.o obj-y += efi_emul.o +obj-y += fw_emul.o obj-y += hpsimserial.o obj-y += hypercall.o obj-y += hyperprivop.o @@ -13,7 +14,7 @@ obj-y += mm.o obj-y += mm_init.o obj-y += pcdp.o obj-y += privop.o -obj-y += process.o +obj-y += faults.o obj-y += regionreg.o obj-y += sn_console.o obj-y += vcpu.o diff --git a/xen/arch/ia64/xen/dom_fw.c b/xen/arch/ia64/xen/dom_fw.c index 2b7855c9c6..0c03f262fd 100644 --- a/xen/arch/ia64/xen/dom_fw.c +++ b/xen/arch/ia64/xen/dom_fw.c @@ -23,7 +23,6 @@ #include #include -#include static struct ia64_boot_param *dom_fw_init(struct domain *, const char *,int,char *,int); extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr); @@ -139,334 +138,6 @@ unsigned long dom_fw_setup(struct domain *d, const char *args, int arglen) /* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */ -struct sal_ret_values -sal_emulator (long index, unsigned long in1, unsigned long in2, - unsigned long in3, unsigned long in4, unsigned long in5, - unsigned long in6, unsigned long in7) -{ - unsigned long r9 = 0; - unsigned long r10 = 0; - long r11 = 0; - long status; - - status = 0; - switch (index) { - case SAL_FREQ_BASE: - if (!running_on_sim) - status = ia64_sal_freq_base(in1,&r9,&r10); - else switch (in1) { - case SAL_FREQ_BASE_PLATFORM: - r9 = 200000000; - break; - - case SAL_FREQ_BASE_INTERVAL_TIMER: - r9 = 700000000; - break; - - case SAL_FREQ_BASE_REALTIME_CLOCK: - r9 = 1; - break; - - default: - status = -1; - break; - } - break; - case SAL_PCI_CONFIG_READ: - if (current->domain == dom0) { - u64 value; - // note that args 2&3 are swapped!! - status = ia64_sal_pci_config_read(in1,in3,in2,&value); - r9 = value; - } - else - printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n"); - break; - case SAL_PCI_CONFIG_WRITE: - if (current->domain == dom0) { - if (((in1 & ~0xffffffffUL) && (in4 == 0)) || - (in4 > 1) || - (in2 > 8) || (in2 & (in2-1))) - printf("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n", - in1,in4,in2,in3); - // note that args are in a different order!! - status = ia64_sal_pci_config_write(in1,in4,in2,in3); - } - else - printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n"); - break; - case SAL_SET_VECTORS: - if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) { - if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) { - /* Sanity check: cs_length1 must be 0, - second vector is reserved. */ - status = -2; - } - else { - struct domain *d = current->domain; - d->arch.boot_rdv_ip = in2; - d->arch.boot_rdv_r1 = in3; - } - } - else - printf("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n", - in1); - break; - case SAL_GET_STATE_INFO: - /* No more info. */ - status = -5; - r9 = 0; - break; - case SAL_GET_STATE_INFO_SIZE: - /* Return a dummy size. */ - status = 0; - r9 = 128; - break; - case SAL_CLEAR_STATE_INFO: - /* Noop. */ - break; - case SAL_MC_RENDEZ: - printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n"); - break; - case SAL_MC_SET_PARAMS: - printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n"); - break; - case SAL_CACHE_FLUSH: - if (1) { - /* Flush using SAL. - This method is faster but has a side effect on - other vcpu running on this cpu. */ - status = ia64_sal_cache_flush (in1); - } - else { - /* Flush with fc all the domain. - This method is slower but has no side effects. */ - domain_cache_flush (current->domain, in1 == 4 ? 1 : 0); - status = 0; - } - break; - case SAL_CACHE_INIT: - printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n"); - break; - case SAL_UPDATE_PAL: - printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n"); - break; - default: - printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n"); - status = -1; - break; - } - return ((struct sal_ret_values) {status, r9, r10, r11}); -} - -struct ia64_pal_retval -xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) -{ - unsigned long r9 = 0; - unsigned long r10 = 0; - unsigned long r11 = 0; - long status = PAL_STATUS_UNIMPLEMENTED; - - if (running_on_sim) - return pal_emulator_static(index); - - // pal code must be mapped by a TR when pal is called, however - // calls are rare enough that we will map it lazily rather than - // at every context switch - //efi_map_pal_code(); - switch (index) { - case PAL_MEM_ATTRIB: - status = ia64_pal_mem_attrib(&r9); - break; - case PAL_FREQ_BASE: - status = ia64_pal_freq_base(&r9); - break; - case PAL_PROC_GET_FEATURES: - status = ia64_pal_proc_get_features(&r9,&r10,&r11); - break; - case PAL_BUS_GET_FEATURES: - status = ia64_pal_bus_get_features( - (pal_bus_features_u_t *) &r9, - (pal_bus_features_u_t *) &r10, - (pal_bus_features_u_t *) &r11); - break; - case PAL_FREQ_RATIOS: - status = ia64_pal_freq_ratios( - (struct pal_freq_ratio *) &r9, - (struct pal_freq_ratio *) &r10, - (struct pal_freq_ratio *) &r11); - break; - case PAL_PTCE_INFO: - { - // return hard-coded xen-specific values because ptc.e - // is emulated on xen to always flush everything - // these values result in only one ptc.e instruction - status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0; - } - break; - case PAL_VERSION: - status = ia64_pal_version( - (pal_version_u_t *) &r9, - (pal_version_u_t *) &r10); - break; - case PAL_VM_PAGE_SIZE: - status = ia64_pal_vm_page_size(&r9,&r10); - break; - case PAL_DEBUG_INFO: - status = ia64_pal_debug_info(&r9,&r10); - break; - case PAL_CACHE_SUMMARY: - status = ia64_pal_cache_summary(&r9,&r10); - break; - case PAL_VM_SUMMARY: - { - /* Use xen-specific values. - hash_tag_id is somewhat random! */ - const pal_vm_info_1_u_t v1 = - {.pal_vm_info_1_s = - { .vw = 1, - .phys_add_size = 44, - .key_size = 16, - .max_pkr = 15, - .hash_tag_id = 0x30, - .max_dtr_entry = NDTRS - 1, - .max_itr_entry = NITRS - 1, -#ifdef VHPT_GLOBAL - .max_unique_tcs = 3, - .num_tc_levels = 2 -#else - .max_unique_tcs = 2, - .num_tc_levels = 1 -#endif - }}; - const pal_vm_info_2_u_t v2 = - { .pal_vm_info_2_s = - { .impl_va_msb = 50, - .rid_size = current->domain->arch.rid_bits, - .reserved = 0 }}; - r9 = v1.pvi1_val; - r10 = v2.pvi2_val; - status = PAL_STATUS_SUCCESS; - } - break; - case PAL_VM_INFO: -#ifdef VHPT_GLOBAL - if (in1 == 0 && in2 == 2) { - /* Level 1: VHPT */ - const pal_tc_info_u_t v = - { .pal_tc_info_s = {.num_sets = 128, - .associativity = 1, - .num_entries = 128, - .pf = 1, - .unified = 1, - .reduce_tr = 0, - .reserved = 0}}; - r9 = v.pti_val; - /* Only support PAGE_SIZE tc. */ - r10 = PAGE_SIZE; - status = PAL_STATUS_SUCCESS; - } -#endif - else if ( -#ifdef VHPT_GLOBAL - in1 == 1 /* Level 2. */ -#else - in1 == 0 /* Level 1. */ -#endif - && (in2 == 1 || in2 == 2)) - { - /* itlb/dtlb, 1 entry. */ - const pal_tc_info_u_t v = - { .pal_tc_info_s = {.num_sets = 1, - .associativity = 1, - .num_entries = 1, - .pf = 1, - .unified = 0, - .reduce_tr = 0, - .reserved = 0}}; - r9 = v.pti_val; - /* Only support PAGE_SIZE tc. */ - r10 = PAGE_SIZE; - status = PAL_STATUS_SUCCESS; - } - else - status = PAL_STATUS_EINVAL; - break; - case PAL_RSE_INFO: - status = ia64_pal_rse_info( - &r9, - (pal_hints_u_t *) &r10); - break; - case PAL_REGISTER_INFO: - status = ia64_pal_register_info(in1, &r9, &r10); - break; - case PAL_CACHE_FLUSH: - /* FIXME */ - printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n"); - BUG(); - break; - case PAL_PERF_MON_INFO: - { - unsigned long pm_buffer[16]; - status = ia64_pal_perf_mon_info( - pm_buffer, - (pal_perf_mon_info_u_t *) &r9); - if (status != 0) { - while(1) - printk("PAL_PERF_MON_INFO fails ret=%ld\n", status); - break; - } - if (copy_to_user((void __user *)in1,pm_buffer,128)) { - while(1) - printk("xen_pal_emulator: PAL_PERF_MON_INFO " - "can't copy to user!!!!\n"); - status = PAL_STATUS_UNIMPLEMENTED; - break; - } - } - break; - case PAL_CACHE_INFO: - { - pal_cache_config_info_t ci; - status = ia64_pal_cache_config_info(in1,in2,&ci); - if (status != 0) break; - r9 = ci.pcci_info_1.pcci1_data; - r10 = ci.pcci_info_2.pcci2_data; - } - break; - case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */ - printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n"); - break; - case PAL_HALT_INFO: - { - /* 1000 cycles to enter/leave low power state, - consumes 10 mW, implemented and cache/TLB coherent. */ - unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32) - | (1UL << 61) | (1UL << 60); - if (copy_to_user ((void *)in1, &res, sizeof (res))) - status = PAL_STATUS_EINVAL; - else - status = PAL_STATUS_SUCCESS; - } - break; - case PAL_HALT: - if (current->domain == dom0) { - printf ("Domain0 halts the machine\n"); - (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL); - } - else - domain_shutdown (current->domain, - SHUTDOWN_poweroff); - break; - default: - printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n", - index); - break; - } - return ((struct ia64_pal_retval) {status, r9, r10, r11}); -} - - #define NFUNCPTRS 20 static void print_md(efi_memory_desc_t *md) @@ -479,7 +150,6 @@ static void print_md(efi_memory_desc_t *md) #endif } - static u32 lsapic_nbr; /* Modify lsapic table. Provides LPs. */ diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index d2d0e300b7..f1969664ee 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -78,21 +78,96 @@ extern char dom0_command_line[]; #define IS_XEN_ADDRESS(d,a) ((a >= d->xen_vastart) && (a <= d->xen_vaend)) /* FIXME: where these declarations should be there ? */ -extern long platform_is_hp_ski(void); extern void serial_input_init(void); static void init_switch_stack(struct vcpu *v); +extern void vmx_do_launch(struct vcpu *); void build_physmap_table(struct domain *d); /* this belongs in include/asm, but there doesn't seem to be a suitable place */ -void arch_domain_destroy(struct domain *d) +unsigned long context_switch_count = 0; + +extern struct vcpu *ia64_switch_to (struct vcpu *next_task); + +#include + +void schedule_tail(struct vcpu *prev) { - BUG_ON(d->arch.mm.pgd != NULL); - if (d->shared_info != NULL) - free_xenheap_page(d->shared_info); + extern char ia64_ivt; + context_saved(prev); + + if (VMX_DOMAIN(current)) { + vmx_do_launch(current); + } else { + ia64_set_iva(&ia64_ivt); + ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | + VHPT_ENABLED); + load_region_regs(current); + vcpu_load_kernel_regs(current); + } +} - domain_flush_destroy (d); +void context_switch(struct vcpu *prev, struct vcpu *next) +{ + uint64_t spsr; + uint64_t pta; - deallocate_rid_range(d); + local_irq_save(spsr); + context_switch_count++; + + __ia64_save_fpu(prev->arch._thread.fph); + __ia64_load_fpu(next->arch._thread.fph); + if (VMX_DOMAIN(prev)) + vmx_save_state(prev); + if (VMX_DOMAIN(next)) + vmx_load_state(next); + /*ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next);*/ + prev = ia64_switch_to(next); + + //cpu_set(smp_processor_id(), current->domain->domain_dirty_cpumask); + + if (!VMX_DOMAIN(current)){ + vcpu_set_next_timer(current); + } + + +// leave this debug for now: it acts as a heartbeat when more than +// one domain is active +{ +static long cnt[16] = { 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50}; +static int i = 100; +int id = ((struct vcpu *)current)->domain->domain_id & 0xf; +if (!cnt[id]--) { cnt[id] = 500000; printk("%x",id); } +if (!i--) { i = 1000000; printk("+"); } +} + + if (VMX_DOMAIN(current)){ + vmx_load_all_rr(current); + }else{ + extern char ia64_ivt; + ia64_set_iva(&ia64_ivt); + if (!is_idle_domain(current->domain)) { + ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | + VHPT_ENABLED); + load_region_regs(current); + vcpu_load_kernel_regs(current); + if (vcpu_timer_expired(current)) + vcpu_pend_timer(current); + }else { + /* When switching to idle domain, only need to disable vhpt + * walker. Then all accesses happen within idle context will + * be handled by TR mapping and identity mapping. + */ + pta = ia64_get_pta(); + ia64_set_pta(pta & ~VHPT_ENABLED); + } + } + local_irq_restore(spsr); + context_saved(prev); +} + +void continue_running(struct vcpu *same) +{ + /* nothing to do */ } static void default_idle(void) @@ -259,6 +334,17 @@ fail_nomem: return -ENOMEM; } +void arch_domain_destroy(struct domain *d) +{ + BUG_ON(d->arch.mm.pgd != NULL); + if (d->shared_info != NULL) + free_xenheap_page(d->shared_info); + + domain_flush_destroy (d); + + deallocate_rid_range(d); +} + void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c) { c->regs = *vcpu_regs (v); @@ -543,7 +629,7 @@ static void loaddomainelfimage(struct domain *d, unsigned long image_start) void alloc_dom0(void) { - if (platform_is_hp_ski()) { + if (running_on_sim) { dom0_size = 128*1024*1024; //FIXME: Should be configurable } #ifdef CONFIG_DOMAIN0_CONTIGUOUS @@ -798,21 +884,21 @@ int construct_dom0(struct domain *d, void machine_restart(char * __unused) { - if (platform_is_hp_ski()) dummy(); + if (running_on_sim) dummy(); printf("machine_restart called: spinning....\n"); while(1); } void machine_halt(void) { - if (platform_is_hp_ski()) dummy(); + if (running_on_sim) dummy(); printf("machine_halt called: spinning....\n"); while(1); } void dummy_called(char *function) { - if (platform_is_hp_ski()) asm("break 0;;"); + if (running_on_sim) asm("break 0;;"); printf("dummy called in %s: spinning....\n", function); while(1); } diff --git a/xen/arch/ia64/xen/process.c b/xen/arch/ia64/xen/faults.c similarity index 67% rename from xen/arch/ia64/xen/process.c rename to xen/arch/ia64/xen/faults.c index 631b5fc209..7637135833 100644 --- a/xen/arch/ia64/xen/process.c +++ b/xen/arch/ia64/xen/faults.c @@ -15,34 +15,22 @@ #include #include -#include /* FOR struct ia64_sal_retval */ - #include -#include #include -#include -//#include #include #include -#include #include #include #include #include #include -#include "hpsim_ssc.h" -#include #include #include extern void die_if_kernel(char *str, struct pt_regs *regs, long err); /* FIXME: where these declarations shold be there ? */ -extern void panic_domain(struct pt_regs *, const char *, ...); -extern long platform_is_hp_ski(void); extern int ia64_hyperprivop(unsigned long, REGS *); extern IA64FAULT ia64_hypercall(struct pt_regs *regs); -extern void vmx_do_launch(struct vcpu *); -extern unsigned long lookup_domain_mpa(struct domain *,unsigned long); #define IA64_PSR_CPL1 (__IA64_UL(1) << IA64_PSR_CPL1_BIT) // note IA64_PSR_PK removed from following, why is this necessary? @@ -57,113 +45,8 @@ extern unsigned long lookup_domain_mpa(struct domain *,unsigned long); IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA) -#include - -void schedule_tail(struct vcpu *prev) -{ - extern char ia64_ivt; - context_saved(prev); - - if (VMX_DOMAIN(current)) { - vmx_do_launch(current); - } else { - ia64_set_iva(&ia64_ivt); - ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | - VHPT_ENABLED); - load_region_regs(current); - vcpu_load_kernel_regs(current); - } -} - -void tdpfoo(void) { } - -// given a domain virtual address, pte and pagesize, extract the metaphysical -// address, convert the pte for a physical address for (possibly different) -// Xen PAGE_SIZE and return modified pte. (NOTE: TLB insert should use -// PAGE_SIZE!) -u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* logps) -{ - struct domain *d = current->domain; - ia64_itir_t itir = {.itir = itir__}; - u64 mask, mpaddr, pteval2; - u64 arflags; - u64 arflags2; - - pteval &= ((1UL << 53) - 1);// ignore [63:53] bits - - // FIXME address had better be pre-validated on insert - mask = ~itir_mask(itir.itir); - mpaddr = (((pteval & ~_PAGE_ED) & _PAGE_PPN_MASK) & ~mask) | - (address & mask); -#ifdef CONFIG_XEN_IA64_DOM0_VP - if (itir.ps > PAGE_SHIFT) { - itir.ps = PAGE_SHIFT; - } -#endif - *logps = itir.ps; -#ifndef CONFIG_XEN_IA64_DOM0_VP - if (d == dom0) { - if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { - /* - printk("translate_domain_pte: out-of-bounds dom0 mpaddr 0x%lx! itc=%lx...\n", - mpaddr, ia64_get_itc()); - */ - tdpfoo(); - } - } - else if ((mpaddr >> PAGE_SHIFT) > d->max_pages) { - /* Address beyond the limit. However the grant table is - also beyond the limit. Display a message if not in the - grant table. */ - if (mpaddr >= IA64_GRANT_TABLE_PADDR - && mpaddr < (IA64_GRANT_TABLE_PADDR - + (ORDER_GRANT_FRAMES << PAGE_SHIFT))) - printf("translate_domain_pte: bad mpa=0x%lx (> 0x%lx)," - "vadr=0x%lx,pteval=0x%lx,itir=0x%lx\n", - mpaddr, (unsigned long)d->max_pages<2 (PL3 is unaffected) - pteval2 = (pteval & ~_PAGE_PPN_MASK) | pteval2; - return pteval2; -} - -// given a current domain metaphysical address, return the physical address -unsigned long translate_domain_mpaddr(unsigned long mpaddr) -{ - unsigned long pteval; -#ifndef CONFIG_XEN_IA64_DOM0_VP - if (current->domain == dom0) { - if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { - printk("translate_domain_mpaddr: out-of-bounds dom0 mpaddr 0x%lx! continuing...\n", - mpaddr); - tdpfoo(); - } - } -#endif - pteval = lookup_domain_mpa(current->domain,mpaddr); - return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK)); -} +extern void do_ssc(unsigned long ssc, struct pt_regs *regs); unsigned long slow_reflect_count[0x80] = { 0 }; unsigned long fast_reflect_count[0x80] = { 0 }; @@ -243,8 +126,6 @@ void reflect_interruption(unsigned long isr, struct pt_regs *regs, unsigned long inc_slow_reflect_count(vector); } -void foodpi(void) {} - static unsigned long pending_false_positive = 0; void reflect_extint(struct pt_regs *regs) @@ -627,120 +508,9 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, unsigned long running_on_sim = 0; -void -do_ssc(unsigned long ssc, struct pt_regs *regs) -{ - unsigned long arg0, arg1, arg2, arg3, retval; - char buf[2]; -/**/ static int last_fd, last_count; // FIXME FIXME FIXME -/**/ // BROKEN FOR MULTIPLE DOMAINS & SMP -/**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat; - - arg0 = vcpu_get_gr(current,32); - switch(ssc) { - case SSC_PUTCHAR: - buf[0] = arg0; - buf[1] = '\0'; - printf(buf); - break; - case SSC_GETCHAR: - retval = ia64_ssc(0,0,0,0,ssc); - vcpu_set_gr(current,8,retval,0); - break; - case SSC_WAIT_COMPLETION: - if (arg0) { // metaphysical address - - arg0 = translate_domain_mpaddr(arg0); -/**/ stat = (struct ssc_disk_stat *)__va(arg0); -///**/ if (stat->fd == last_fd) stat->count = last_count; -/**/ stat->count = last_count; -//if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count); -///**/ retval = ia64_ssc(arg0,0,0,0,ssc); -/**/ retval = 0; - } - else retval = -1L; - vcpu_set_gr(current,8,retval,0); - break; - case SSC_OPEN: - arg1 = vcpu_get_gr(current,33); // access rights -if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; } - if (arg0) { // metaphysical address - arg0 = translate_domain_mpaddr(arg0); - retval = ia64_ssc(arg0,arg1,0,0,ssc); - } - else retval = -1L; - vcpu_set_gr(current,8,retval,0); - break; - case SSC_WRITE: - case SSC_READ: -//if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n"); - arg1 = vcpu_get_gr(current,33); - arg2 = vcpu_get_gr(current,34); - arg3 = vcpu_get_gr(current,35); - if (arg2) { // metaphysical address of descriptor - struct ssc_disk_req *req; - unsigned long mpaddr; - long len; - - arg2 = translate_domain_mpaddr(arg2); - req = (struct ssc_disk_req *) __va(arg2); - req->len &= 0xffffffffL; // avoid strange bug - len = req->len; -/**/ last_fd = arg1; -/**/ last_count = len; - mpaddr = req->addr; -//if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len); - retval = 0; - if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) { - // do partial page first - req->addr = translate_domain_mpaddr(mpaddr); - req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK); - len -= req->len; mpaddr += req->len; - retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); - arg3 += req->len; // file offset -/**/ last_stat.fd = last_fd; -/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); -//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval); - } - if (retval >= 0) while (len > 0) { - req->addr = translate_domain_mpaddr(mpaddr); - req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len; - len -= PAGE_SIZE; mpaddr += PAGE_SIZE; - retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); - arg3 += req->len; // file offset -// TEMP REMOVED AGAIN arg3 += req->len; // file offset -/**/ last_stat.fd = last_fd; -/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); -//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval); - } - // set it back to the original value - req->len = last_count; - } - else retval = -1L; - vcpu_set_gr(current,8,retval,0); -//if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval); - break; - case SSC_CONNECT_INTERRUPT: - arg1 = vcpu_get_gr(current,33); - arg2 = vcpu_get_gr(current,34); - arg3 = vcpu_get_gr(current,35); - if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; } - (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc); - break; - case SSC_NETDEV_PROBE: - vcpu_set_gr(current,8,-1L,0); - break; - default: - printf("ia64_handle_break: bad ssc code %lx, iip=0x%lx, b0=0x%lx... spinning\n", - ssc, regs->cr_iip, regs->b0); - while(1); - break; - } - vcpu_increment_iip(current); -} /* Also read in hyperprivop.S */ -int first_break = 1; +int first_break = 0; void ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) @@ -749,11 +519,6 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, u struct vcpu *v = current; IA64FAULT vector; - if (first_break) { - if (platform_is_hp_ski()) running_on_sim = 1; - else running_on_sim = 0; - first_break = 0; - } if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant do_ssc(vcpu_get_gr(current,36), regs); } @@ -895,55 +660,3 @@ ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long i reflect_interruption(isr,regs,vector); } -unsigned long hypercall_create_continuation( - unsigned int op, const char *format, ...) -{ - struct mc_state *mcs = &mc_state[smp_processor_id()]; - struct vcpu *v = current; - const char *p = format; - unsigned long arg; - unsigned int i; - va_list args; - - va_start(args, format); - if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) { - panic("PREEMPT happen in multicall\n"); // Not support yet - } else { - vcpu_set_gr(v, 2, op, 0); - for ( i = 0; *p != '\0'; i++) { - switch ( *p++ ) - { - case 'i': - arg = (unsigned long)va_arg(args, unsigned int); - break; - case 'l': - arg = (unsigned long)va_arg(args, unsigned long); - break; - case 'h': - arg = (unsigned long)va_arg(args, void *); - break; - default: - arg = 0; - BUG(); - } - switch (i) { - case 0: vcpu_set_gr(v, 14, arg, 0); - break; - case 1: vcpu_set_gr(v, 15, arg, 0); - break; - case 2: vcpu_set_gr(v, 16, arg, 0); - break; - case 3: vcpu_set_gr(v, 17, arg, 0); - break; - case 4: vcpu_set_gr(v, 18, arg, 0); - break; - default: panic("Too many args for hypercall continuation\n"); - break; - } - } - } - v->arch.hypercall_continuation = 1; - va_end(args); - return op; -} - diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c new file mode 100644 index 0000000000..611e9ed9b0 --- /dev/null +++ b/xen/arch/ia64/xen/fw_emul.c @@ -0,0 +1,453 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include "hpsim_ssc.h" +#include +#include + +extern unsigned long running_on_sim; + +struct sal_ret_values +sal_emulator (long index, unsigned long in1, unsigned long in2, + unsigned long in3, unsigned long in4, unsigned long in5, + unsigned long in6, unsigned long in7) +{ + unsigned long r9 = 0; + unsigned long r10 = 0; + long r11 = 0; + long status; + + status = 0; + switch (index) { + case SAL_FREQ_BASE: + if (!running_on_sim) + status = ia64_sal_freq_base(in1,&r9,&r10); + else switch (in1) { + case SAL_FREQ_BASE_PLATFORM: + r9 = 200000000; + break; + + case SAL_FREQ_BASE_INTERVAL_TIMER: + r9 = 700000000; + break; + + case SAL_FREQ_BASE_REALTIME_CLOCK: + r9 = 1; + break; + + default: + status = -1; + break; + } + break; + case SAL_PCI_CONFIG_READ: + if (current->domain == dom0) { + u64 value; + // note that args 2&3 are swapped!! + status = ia64_sal_pci_config_read(in1,in3,in2,&value); + r9 = value; + } + else + printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n"); + break; + case SAL_PCI_CONFIG_WRITE: + if (current->domain == dom0) { + if (((in1 & ~0xffffffffUL) && (in4 == 0)) || + (in4 > 1) || + (in2 > 8) || (in2 & (in2-1))) + printf("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n", + in1,in4,in2,in3); + // note that args are in a different order!! + status = ia64_sal_pci_config_write(in1,in4,in2,in3); + } + else + printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n"); + break; + case SAL_SET_VECTORS: + if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) { + if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) { + /* Sanity check: cs_length1 must be 0, + second vector is reserved. */ + status = -2; + } + else { + struct domain *d = current->domain; + d->arch.boot_rdv_ip = in2; + d->arch.boot_rdv_r1 = in3; + } + } + else + printf("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n", + in1); + break; + case SAL_GET_STATE_INFO: + /* No more info. */ + status = -5; + r9 = 0; + break; + case SAL_GET_STATE_INFO_SIZE: + /* Return a dummy size. */ + status = 0; + r9 = 128; + break; + case SAL_CLEAR_STATE_INFO: + /* Noop. */ + break; + case SAL_MC_RENDEZ: + printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n"); + break; + case SAL_MC_SET_PARAMS: + printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n"); + break; + case SAL_CACHE_FLUSH: + if (1) { + /* Flush using SAL. + This method is faster but has a side effect on + other vcpu running on this cpu. */ + status = ia64_sal_cache_flush (in1); + } + else { + /* Flush with fc all the domain. + This method is slower but has no side effects. */ + domain_cache_flush (current->domain, in1 == 4 ? 1 : 0); + status = 0; + } + break; + case SAL_CACHE_INIT: + printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n"); + break; + case SAL_UPDATE_PAL: + printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n"); + break; + default: + printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n"); + status = -1; + break; + } + return ((struct sal_ret_values) {status, r9, r10, r11}); +} + +struct ia64_pal_retval +xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) +{ + unsigned long r9 = 0; + unsigned long r10 = 0; + unsigned long r11 = 0; + long status = PAL_STATUS_UNIMPLEMENTED; + + if (running_on_sim) + return pal_emulator_static(index); + + // pal code must be mapped by a TR when pal is called, however + // calls are rare enough that we will map it lazily rather than + // at every context switch + //efi_map_pal_code(); + switch (index) { + case PAL_MEM_ATTRIB: + status = ia64_pal_mem_attrib(&r9); + break; + case PAL_FREQ_BASE: + status = ia64_pal_freq_base(&r9); + break; + case PAL_PROC_GET_FEATURES: + status = ia64_pal_proc_get_features(&r9,&r10,&r11); + break; + case PAL_BUS_GET_FEATURES: + status = ia64_pal_bus_get_features( + (pal_bus_features_u_t *) &r9, + (pal_bus_features_u_t *) &r10, + (pal_bus_features_u_t *) &r11); + break; + case PAL_FREQ_RATIOS: + status = ia64_pal_freq_ratios( + (struct pal_freq_ratio *) &r9, + (struct pal_freq_ratio *) &r10, + (struct pal_freq_ratio *) &r11); + break; + case PAL_PTCE_INFO: + { + // return hard-coded xen-specific values because ptc.e + // is emulated on xen to always flush everything + // these values result in only one ptc.e instruction + status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0; + } + break; + case PAL_VERSION: + status = ia64_pal_version( + (pal_version_u_t *) &r9, + (pal_version_u_t *) &r10); + break; + case PAL_VM_PAGE_SIZE: + status = ia64_pal_vm_page_size(&r9,&r10); + break; + case PAL_DEBUG_INFO: + status = ia64_pal_debug_info(&r9,&r10); + break; + case PAL_CACHE_SUMMARY: + status = ia64_pal_cache_summary(&r9,&r10); + break; + case PAL_VM_SUMMARY: + { + /* Use xen-specific values. + hash_tag_id is somewhat random! */ + const pal_vm_info_1_u_t v1 = + {.pal_vm_info_1_s = + { .vw = 1, + .phys_add_size = 44, + .key_size = 16, + .max_pkr = 15, + .hash_tag_id = 0x30, + .max_dtr_entry = NDTRS - 1, + .max_itr_entry = NITRS - 1, +#ifdef VHPT_GLOBAL + .max_unique_tcs = 3, + .num_tc_levels = 2 +#else + .max_unique_tcs = 2, + .num_tc_levels = 1 +#endif + }}; + const pal_vm_info_2_u_t v2 = + { .pal_vm_info_2_s = + { .impl_va_msb = 50, + .rid_size = current->domain->arch.rid_bits, + .reserved = 0 }}; + r9 = v1.pvi1_val; + r10 = v2.pvi2_val; + status = PAL_STATUS_SUCCESS; + } + break; + case PAL_VM_INFO: +#ifdef VHPT_GLOBAL + if (in1 == 0 && in2 == 2) { + /* Level 1: VHPT */ + const pal_tc_info_u_t v = + { .pal_tc_info_s = {.num_sets = 128, + .associativity = 1, + .num_entries = 128, + .pf = 1, + .unified = 1, + .reduce_tr = 0, + .reserved = 0}}; + r9 = v.pti_val; + /* Only support PAGE_SIZE tc. */ + r10 = PAGE_SIZE; + status = PAL_STATUS_SUCCESS; + } +#endif + else if ( +#ifdef VHPT_GLOBAL + in1 == 1 /* Level 2. */ +#else + in1 == 0 /* Level 1. */ +#endif + && (in2 == 1 || in2 == 2)) + { + /* itlb/dtlb, 1 entry. */ + const pal_tc_info_u_t v = + { .pal_tc_info_s = {.num_sets = 1, + .associativity = 1, + .num_entries = 1, + .pf = 1, + .unified = 0, + .reduce_tr = 0, + .reserved = 0}}; + r9 = v.pti_val; + /* Only support PAGE_SIZE tc. */ + r10 = PAGE_SIZE; + status = PAL_STATUS_SUCCESS; + } + else + status = PAL_STATUS_EINVAL; + break; + case PAL_RSE_INFO: + status = ia64_pal_rse_info( + &r9, + (pal_hints_u_t *) &r10); + break; + case PAL_REGISTER_INFO: + status = ia64_pal_register_info(in1, &r9, &r10); + break; + case PAL_CACHE_FLUSH: + /* FIXME */ + printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n"); + BUG(); + break; + case PAL_PERF_MON_INFO: + { + unsigned long pm_buffer[16]; + status = ia64_pal_perf_mon_info( + pm_buffer, + (pal_perf_mon_info_u_t *) &r9); + if (status != 0) { + while(1) + printk("PAL_PERF_MON_INFO fails ret=%ld\n", status); + break; + } + if (copy_to_user((void __user *)in1,pm_buffer,128)) { + while(1) + printk("xen_pal_emulator: PAL_PERF_MON_INFO " + "can't copy to user!!!!\n"); + status = PAL_STATUS_UNIMPLEMENTED; + break; + } + } + break; + case PAL_CACHE_INFO: + { + pal_cache_config_info_t ci; + status = ia64_pal_cache_config_info(in1,in2,&ci); + if (status != 0) break; + r9 = ci.pcci_info_1.pcci1_data; + r10 = ci.pcci_info_2.pcci2_data; + } + break; + case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */ + printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n"); + break; + case PAL_HALT_INFO: + { + /* 1000 cycles to enter/leave low power state, + consumes 10 mW, implemented and cache/TLB coherent. */ + unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32) + | (1UL << 61) | (1UL << 60); + if (copy_to_user ((void *)in1, &res, sizeof (res))) + status = PAL_STATUS_EINVAL; + else + status = PAL_STATUS_SUCCESS; + } + break; + case PAL_HALT: + if (current->domain == dom0) { + printf ("Domain0 halts the machine\n"); + (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL); + } + else + domain_shutdown (current->domain, + SHUTDOWN_poweroff); + break; + default: + printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n", + index); + break; + } + return ((struct ia64_pal_retval) {status, r9, r10, r11}); +} + +void +do_ssc(unsigned long ssc, struct pt_regs *regs) +{ + unsigned long arg0, arg1, arg2, arg3, retval; + char buf[2]; +/**/ static int last_fd, last_count; // FIXME FIXME FIXME +/**/ // BROKEN FOR MULTIPLE DOMAINS & SMP +/**/ struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat; + + arg0 = vcpu_get_gr(current,32); + switch(ssc) { + case SSC_PUTCHAR: + buf[0] = arg0; + buf[1] = '\0'; + printf(buf); + break; + case SSC_GETCHAR: + retval = ia64_ssc(0,0,0,0,ssc); + vcpu_set_gr(current,8,retval,0); + break; + case SSC_WAIT_COMPLETION: + if (arg0) { // metaphysical address + + arg0 = translate_domain_mpaddr(arg0); +/**/ stat = (struct ssc_disk_stat *)__va(arg0); +///**/ if (stat->fd == last_fd) stat->count = last_count; +/**/ stat->count = last_count; +//if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count); +///**/ retval = ia64_ssc(arg0,0,0,0,ssc); +/**/ retval = 0; + } + else retval = -1L; + vcpu_set_gr(current,8,retval,0); + break; + case SSC_OPEN: + arg1 = vcpu_get_gr(current,33); // access rights +if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware. (ignoring...)\n"); arg0 = 0; } + if (arg0) { // metaphysical address + arg0 = translate_domain_mpaddr(arg0); + retval = ia64_ssc(arg0,arg1,0,0,ssc); + } + else retval = -1L; + vcpu_set_gr(current,8,retval,0); + break; + case SSC_WRITE: + case SSC_READ: +//if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n"); + arg1 = vcpu_get_gr(current,33); + arg2 = vcpu_get_gr(current,34); + arg3 = vcpu_get_gr(current,35); + if (arg2) { // metaphysical address of descriptor + struct ssc_disk_req *req; + unsigned long mpaddr; + long len; + + arg2 = translate_domain_mpaddr(arg2); + req = (struct ssc_disk_req *) __va(arg2); + req->len &= 0xffffffffL; // avoid strange bug + len = req->len; +/**/ last_fd = arg1; +/**/ last_count = len; + mpaddr = req->addr; +//if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len); + retval = 0; + if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) { + // do partial page first + req->addr = translate_domain_mpaddr(mpaddr); + req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK); + len -= req->len; mpaddr += req->len; + retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); + arg3 += req->len; // file offset +/**/ last_stat.fd = last_fd; +/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); +//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval); + } + if (retval >= 0) while (len > 0) { + req->addr = translate_domain_mpaddr(mpaddr); + req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len; + len -= PAGE_SIZE; mpaddr += PAGE_SIZE; + retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc); + arg3 += req->len; // file offset +// TEMP REMOVED AGAIN arg3 += req->len; // file offset +/**/ last_stat.fd = last_fd; +/**/ (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION); +//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval); + } + // set it back to the original value + req->len = last_count; + } + else retval = -1L; + vcpu_set_gr(current,8,retval,0); +//if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval); + break; + case SSC_CONNECT_INTERRUPT: + arg1 = vcpu_get_gr(current,33); + arg2 = vcpu_get_gr(current,34); + arg3 = vcpu_get_gr(current,35); + if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware. (ignoring...)\n"); break; } + (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc); + break; + case SSC_NETDEV_PROBE: + vcpu_set_gr(current,8,-1L,0); + break; + default: + printf("ia64_handle_break: bad ssc code %lx, iip=0x%lx, b0=0x%lx... spinning\n", + ssc, regs->cr_iip, regs->b0); + while(1); + break; + } + vcpu_increment_iip(current); +} diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index a5b5fb428c..e02783503e 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -334,6 +334,58 @@ ia64_hypercall (struct pt_regs *regs) return xen_hypercall (regs); } +unsigned long hypercall_create_continuation( + unsigned int op, const char *format, ...) +{ + struct mc_state *mcs = &mc_state[smp_processor_id()]; + struct vcpu *v = current; + const char *p = format; + unsigned long arg; + unsigned int i; + va_list args; + + va_start(args, format); + if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) { + panic("PREEMPT happen in multicall\n"); // Not support yet + } else { + vcpu_set_gr(v, 2, op, 0); + for ( i = 0; *p != '\0'; i++) { + switch ( *p++ ) + { + case 'i': + arg = (unsigned long)va_arg(args, unsigned int); + break; + case 'l': + arg = (unsigned long)va_arg(args, unsigned long); + break; + case 'h': + arg = (unsigned long)va_arg(args, void *); + break; + default: + arg = 0; + BUG(); + } + switch (i) { + case 0: vcpu_set_gr(v, 14, arg, 0); + break; + case 1: vcpu_set_gr(v, 15, arg, 0); + break; + case 2: vcpu_set_gr(v, 16, arg, 0); + break; + case 3: vcpu_set_gr(v, 17, arg, 0); + break; + case 4: vcpu_set_gr(v, 18, arg, 0); + break; + default: panic("Too many args for hypercall continuation\n"); + break; + } + } + } + v->arch.hypercall_continuation = 1; + va_end(args); + return op; +} + /* Need make this function common */ extern int iosapic_guest_read( diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index b33bbf4ead..5a3f2381e5 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #ifndef CONFIG_XEN_IA64_DOM0_VP @@ -248,6 +249,110 @@ share_xen_page_with_privileged_guests(struct page_info *page, int readonly) share_xen_page_with_guest(page, dom_xen, readonly); } +unsigned long +gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) +{ + unsigned long pte; + +#ifndef CONFIG_XEN_IA64_DOM0_VP + if (d == dom0) + return(gpfn); +#endif + pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT); + if (!pte) { + panic("gmfn_to_mfn_foreign: bad gpfn. spinning...\n"); + } + return ((pte & _PFN_MASK) >> PAGE_SHIFT); +} + +// given a domain virtual address, pte and pagesize, extract the metaphysical +// address, convert the pte for a physical address for (possibly different) +// Xen PAGE_SIZE and return modified pte. (NOTE: TLB insert should use +// PAGE_SIZE!) +u64 translate_domain_pte(u64 pteval, u64 address, u64 itir__, u64* logps) +{ + struct domain *d = current->domain; + ia64_itir_t itir = {.itir = itir__}; + u64 mask, mpaddr, pteval2; + u64 arflags; + u64 arflags2; + + pteval &= ((1UL << 53) - 1);// ignore [63:53] bits + + // FIXME address had better be pre-validated on insert + mask = ~itir_mask(itir.itir); + mpaddr = (((pteval & ~_PAGE_ED) & _PAGE_PPN_MASK) & ~mask) | + (address & mask); +#ifdef CONFIG_XEN_IA64_DOM0_VP + if (itir.ps > PAGE_SHIFT) { + itir.ps = PAGE_SHIFT; + } +#endif + *logps = itir.ps; +#ifndef CONFIG_XEN_IA64_DOM0_VP + if (d == dom0) { + if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { + /* + printk("translate_domain_pte: out-of-bounds dom0 mpaddr 0x%lx! itc=%lx...\n", + mpaddr, ia64_get_itc()); + */ + tdpfoo(); + } + } + else if ((mpaddr >> PAGE_SHIFT) > d->max_pages) { + /* Address beyond the limit. However the grant table is + also beyond the limit. Display a message if not in the + grant table. */ + if (mpaddr >= IA64_GRANT_TABLE_PADDR + && mpaddr < (IA64_GRANT_TABLE_PADDR + + (ORDER_GRANT_FRAMES << PAGE_SHIFT))) + printf("translate_domain_pte: bad mpa=0x%lx (> 0x%lx)," + "vadr=0x%lx,pteval=0x%lx,itir=0x%lx\n", + mpaddr, (unsigned long)d->max_pages<2 (PL3 is unaffected) + pteval2 = (pteval & ~_PAGE_PPN_MASK) | pteval2; + return pteval2; +} + +// given a current domain metaphysical address, return the physical address +unsigned long translate_domain_mpaddr(unsigned long mpaddr) +{ + unsigned long pteval; + +#ifndef CONFIG_XEN_IA64_DOM0_VP + if (current->domain == dom0) { + if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) { + printk("translate_domain_mpaddr: out-of-bounds dom0 mpaddr 0x%lx! continuing...\n", + mpaddr); + tdpfoo(); + } + } +#endif + pteval = lookup_domain_mpa(current->domain,mpaddr); + return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK)); +} + //XXX !xxx_present() should be used instread of !xxx_none()? static pte_t* lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr) @@ -1036,6 +1141,238 @@ void domain_cache_flush (struct domain *d, int sync_only) //printf ("domain_cache_flush: %d %d pages\n", d->domain_id, nbr_page); } +#ifdef VERBOSE +#define MEM_LOG(_f, _a...) \ + printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \ + current->domain->domain_id , __LINE__ , ## _a ) +#else +#define MEM_LOG(_f, _a...) ((void)0) +#endif + +static void free_page_type(struct page_info *page, u32 type) +{ +} + +static int alloc_page_type(struct page_info *page, u32 type) +{ + return 1; +} + +unsigned long __get_free_pages(unsigned int mask, unsigned int order) +{ + void *p = alloc_xenheap_pages(order); + + memset(p,0,PAGE_SIZE<u.inuse.type_info; + + again: + do { + x = y; + nx = x - 1; + + ASSERT((x & PGT_count_mask) != 0); + + /* + * The page should always be validated while a reference is held. The + * exception is during domain destruction, when we forcibly invalidate + * page-table pages if we detect a referential loop. + * See domain.c:relinquish_list(). + */ + ASSERT((x & PGT_validated) || + test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags)); + + if ( unlikely((nx & PGT_count_mask) == 0) ) + { + /* Record TLB information for flush later. Races are harmless. */ + page->tlbflush_timestamp = tlbflush_current_time(); + + if ( unlikely((nx & PGT_type_mask) <= PGT_l4_page_table) && + likely(nx & PGT_validated) ) + { + /* + * Page-table pages must be unvalidated when count is zero. The + * 'free' is safe because the refcnt is non-zero and validated + * bit is clear => other ops will spin or fail. + */ + if ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, + x & ~PGT_validated)) != x) ) + goto again; + /* We cleared the 'valid bit' so we do the clean up. */ + free_page_type(page, x); + /* Carry on, but with the 'valid bit' now clear. */ + x &= ~PGT_validated; + nx &= ~PGT_validated; + } + } + else if ( unlikely(((nx & (PGT_pinned | PGT_count_mask)) == + (PGT_pinned | 1)) && + ((nx & PGT_type_mask) != PGT_writable_page)) ) + { + /* Page is now only pinned. Make the back pointer mutable again. */ + nx |= PGT_va_mutable; + } + } + while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); +} + + +int get_page_type(struct page_info *page, u32 type) +{ + u32 nx, x, y = page->u.inuse.type_info; + + again: + do { + x = y; + nx = x + 1; + if ( unlikely((nx & PGT_count_mask) == 0) ) + { + MEM_LOG("Type count overflow on pfn %lx", page_to_mfn(page)); + return 0; + } + else if ( unlikely((x & PGT_count_mask) == 0) ) + { + if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) + { + if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) + { + /* + * On type change we check to flush stale TLB + * entries. This may be unnecessary (e.g., page + * was GDT/LDT) but those circumstances should be + * very rare. + */ + cpumask_t mask = + page_get_owner(page)->domain_dirty_cpumask; + tlbflush_filter(mask, page->tlbflush_timestamp); + + if ( unlikely(!cpus_empty(mask)) ) + { + perfc_incrc(need_flush_tlb_flush); + flush_tlb_mask(mask); + } + } + + /* We lose existing type, back pointer, and validity. */ + nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); + nx |= type; + + /* No special validation needed for writable pages. */ + /* Page tables and GDT/LDT need to be scanned for validity. */ + if ( type == PGT_writable_page ) + nx |= PGT_validated; + } + } + else + { + if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) + { + if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) + { + if ( current->domain == page_get_owner(page) ) + { + /* + * This ensures functions like set_gdt() see up-to-date + * type info without needing to clean up writable p.t. + * state on the fast path. + */ + LOCK_BIGLOCK(current->domain); + cleanup_writable_pagetable(current->domain); + y = page->u.inuse.type_info; + UNLOCK_BIGLOCK(current->domain); + /* Can we make progress now? */ + if ( ((y & PGT_type_mask) == (type & PGT_type_mask)) || + ((y & PGT_count_mask) == 0) ) + goto again; + } + if ( ((x & PGT_type_mask) != PGT_l2_page_table) || + ((type & PGT_type_mask) != PGT_l1_page_table) ) + MEM_LOG("Bad type (saw %08x != exp %08x) " + "for mfn %016lx (pfn %016lx)", + x, type, page_to_mfn(page), + get_gpfn_from_mfn(page_to_mfn(page))); + return 0; + } + else if ( (x & PGT_va_mask) == PGT_va_mutable ) + { + /* The va backpointer is mutable, hence we update it. */ + nx &= ~PGT_va_mask; + nx |= type; /* we know the actual type is correct */ + } + else if ( ((type & PGT_va_mask) != PGT_va_mutable) && + ((type & PGT_va_mask) != (x & PGT_va_mask)) ) + { +#ifdef CONFIG_X86_PAE + /* We use backptr as extra typing. Cannot be unknown. */ + if ( (type & PGT_type_mask) == PGT_l2_page_table ) + return 0; +#endif + /* This table is possibly mapped at multiple locations. */ + nx &= ~PGT_va_mask; + nx |= PGT_va_unknown; + } + } + if ( unlikely(!(x & PGT_validated)) ) + { + /* Someone else is updating validation of this page. Wait... */ + while ( (y = page->u.inuse.type_info) == x ) + cpu_relax(); + goto again; + } + } + } + while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); + + if ( unlikely(!(nx & PGT_validated)) ) + { + /* Try to validate page type; drop the new reference on failure. */ + if ( unlikely(!alloc_page_type(page, type)) ) + { + MEM_LOG("Error while validating mfn %lx (pfn %lx) for type %08x" + ": caf=%08x taf=%" PRtype_info, + page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)), + type, page->count_info, page->u.inuse.type_info); + /* Noone else can get a reference. We hold the only ref. */ + page->u.inuse.type_info = 0; + return 0; + } + + /* Noone else is updating simultaneously. */ + __set_bit(_PGT_validated, &page->u.inuse.type_info); + } + + return 1; +} + /* * Local variables: * mode: C diff --git a/xen/arch/ia64/xen/xenmisc.c b/xen/arch/ia64/xen/xenmisc.c index d4dd4062e4..29f8d11e5f 100644 --- a/xen/arch/ia64/xen/xenmisc.c +++ b/xen/arch/ia64/xen/xenmisc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -56,91 +55,8 @@ is_platform_hp_ski(void) return 1; } -long -platform_is_hp_ski(void) -{ - extern long running_on_sim; - return running_on_sim; -} - - struct pt_regs *guest_cpu_user_regs(void) { return vcpu_regs(current); } -unsigned long -gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) -{ - unsigned long pte; - -#ifndef CONFIG_XEN_IA64_DOM0_VP - if (d == dom0) - return(gpfn); -#endif - pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT); - if (!pte) { - panic("gmfn_to_mfn_foreign: bad gpfn. spinning...\n"); - } - return ((pte & _PFN_MASK) >> PAGE_SHIFT); -} - -#if 0 -u32 -mfn_to_gmfn(struct domain *d, unsigned long frame) -{ - // FIXME: is this right? -if ((frame << PAGE_SHIFT) & _PAGE_PPN_MASK) { -printk("mfn_to_gmfn: bad frame. spinning...\n"); -while(1); -} - return frame; -} -#endif - -/////////////////////////////// -// from arch/x86/memory.c -/////////////////////////////// - - -static void free_page_type(struct page_info *page, u32 type) -{ -} - -static int alloc_page_type(struct page_info *page, u32 type) -{ - return 1; -} - -/////////////////////////////// -//// misc memory stuff -/////////////////////////////// - -unsigned long __get_free_pages(unsigned int mask, unsigned int order) -{ - void *p = alloc_xenheap_pages(order); - - memset(p,0,PAGE_SIZE<arch._thread.fph); - __ia64_load_fpu(next->arch._thread.fph); - if (VMX_DOMAIN(prev)) - vmx_save_state(prev); - if (VMX_DOMAIN(next)) - vmx_load_state(next); - /*ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next);*/ - prev = ia64_switch_to(next); - - //cpu_set(smp_processor_id(), current->domain->domain_dirty_cpumask); - - if (!VMX_DOMAIN(current)){ - vcpu_set_next_timer(current); - } - - -// leave this debug for now: it acts as a heartbeat when more than -// one domain is active -{ -static long cnt[16] = { 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50}; -static int i = 100; -int id = ((struct vcpu *)current)->domain->domain_id & 0xf; -if (!cnt[id]--) { cnt[id] = 500000; printk("%x",id); } -if (!i--) { i = 1000000; printk("+"); } -} - - if (VMX_DOMAIN(current)){ - vmx_load_all_rr(current); - }else{ - extern char ia64_ivt; - ia64_set_iva(&ia64_ivt); - if (!is_idle_domain(current->domain)) { - ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | - VHPT_ENABLED); - load_region_regs(current); - vcpu_load_kernel_regs(current); - if (vcpu_timer_expired(current)) - vcpu_pend_timer(current); - }else { - /* When switching to idle domain, only need to disable vhpt - * walker. Then all accesses happen within idle context will - * be handled by TR mapping and identity mapping. - */ - pta = ia64_get_pta(); - ia64_set_pta(pta & ~VHPT_ENABLED); - } - } - local_irq_restore(spsr); - context_saved(prev); -} - -void continue_running(struct vcpu *same) -{ - /* nothing to do */ -} void arch_dump_domain_info(struct domain *d) { @@ -340,202 +188,3 @@ void panic_domain(struct pt_regs *regs, const char *fmt, ...) } domain_crash_synchronous (); } - -/////////////////////////////// -// from arch/x86/mm.c -/////////////////////////////// - -#ifdef VERBOSE -#define MEM_LOG(_f, _a...) \ - printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \ - current->domain->domain_id , __LINE__ , ## _a ) -#else -#define MEM_LOG(_f, _a...) ((void)0) -#endif - -void cleanup_writable_pagetable(struct domain *d) -{ - return; -} - -void put_page_type(struct page_info *page) -{ - u32 nx, x, y = page->u.inuse.type_info; - - again: - do { - x = y; - nx = x - 1; - - ASSERT((x & PGT_count_mask) != 0); - - /* - * The page should always be validated while a reference is held. The - * exception is during domain destruction, when we forcibly invalidate - * page-table pages if we detect a referential loop. - * See domain.c:relinquish_list(). - */ - ASSERT((x & PGT_validated) || - test_bit(_DOMF_dying, &page_get_owner(page)->domain_flags)); - - if ( unlikely((nx & PGT_count_mask) == 0) ) - { - /* Record TLB information for flush later. Races are harmless. */ - page->tlbflush_timestamp = tlbflush_current_time(); - - if ( unlikely((nx & PGT_type_mask) <= PGT_l4_page_table) && - likely(nx & PGT_validated) ) - { - /* - * Page-table pages must be unvalidated when count is zero. The - * 'free' is safe because the refcnt is non-zero and validated - * bit is clear => other ops will spin or fail. - */ - if ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, - x & ~PGT_validated)) != x) ) - goto again; - /* We cleared the 'valid bit' so we do the clean up. */ - free_page_type(page, x); - /* Carry on, but with the 'valid bit' now clear. */ - x &= ~PGT_validated; - nx &= ~PGT_validated; - } - } - else if ( unlikely(((nx & (PGT_pinned | PGT_count_mask)) == - (PGT_pinned | 1)) && - ((nx & PGT_type_mask) != PGT_writable_page)) ) - { - /* Page is now only pinned. Make the back pointer mutable again. */ - nx |= PGT_va_mutable; - } - } - while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); -} - - -int get_page_type(struct page_info *page, u32 type) -{ - u32 nx, x, y = page->u.inuse.type_info; - - again: - do { - x = y; - nx = x + 1; - if ( unlikely((nx & PGT_count_mask) == 0) ) - { - MEM_LOG("Type count overflow on pfn %lx", page_to_mfn(page)); - return 0; - } - else if ( unlikely((x & PGT_count_mask) == 0) ) - { - if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) - { - if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) - { - /* - * On type change we check to flush stale TLB - * entries. This may be unnecessary (e.g., page - * was GDT/LDT) but those circumstances should be - * very rare. - */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; - tlbflush_filter(mask, page->tlbflush_timestamp); - - if ( unlikely(!cpus_empty(mask)) ) - { - perfc_incrc(need_flush_tlb_flush); - flush_tlb_mask(mask); - } - } - - /* We lose existing type, back pointer, and validity. */ - nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); - nx |= type; - - /* No special validation needed for writable pages. */ - /* Page tables and GDT/LDT need to be scanned for validity. */ - if ( type == PGT_writable_page ) - nx |= PGT_validated; - } - } - else - { - if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) - { - if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) - { - if ( current->domain == page_get_owner(page) ) - { - /* - * This ensures functions like set_gdt() see up-to-date - * type info without needing to clean up writable p.t. - * state on the fast path. - */ - LOCK_BIGLOCK(current->domain); - cleanup_writable_pagetable(current->domain); - y = page->u.inuse.type_info; - UNLOCK_BIGLOCK(current->domain); - /* Can we make progress now? */ - if ( ((y & PGT_type_mask) == (type & PGT_type_mask)) || - ((y & PGT_count_mask) == 0) ) - goto again; - } - if ( ((x & PGT_type_mask) != PGT_l2_page_table) || - ((type & PGT_type_mask) != PGT_l1_page_table) ) - MEM_LOG("Bad type (saw %08x != exp %08x) " - "for mfn %016lx (pfn %016lx)", - x, type, page_to_mfn(page), - get_gpfn_from_mfn(page_to_mfn(page))); - return 0; - } - else if ( (x & PGT_va_mask) == PGT_va_mutable ) - { - /* The va backpointer is mutable, hence we update it. */ - nx &= ~PGT_va_mask; - nx |= type; /* we know the actual type is correct */ - } - else if ( ((type & PGT_va_mask) != PGT_va_mutable) && - ((type & PGT_va_mask) != (x & PGT_va_mask)) ) - { -#ifdef CONFIG_X86_PAE - /* We use backptr as extra typing. Cannot be unknown. */ - if ( (type & PGT_type_mask) == PGT_l2_page_table ) - return 0; -#endif - /* This table is possibly mapped at multiple locations. */ - nx &= ~PGT_va_mask; - nx |= PGT_va_unknown; - } - } - if ( unlikely(!(x & PGT_validated)) ) - { - /* Someone else is updating validation of this page. Wait... */ - while ( (y = page->u.inuse.type_info) == x ) - cpu_relax(); - goto again; - } - } - } - while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); - - if ( unlikely(!(nx & PGT_validated)) ) - { - /* Try to validate page type; drop the new reference on failure. */ - if ( unlikely(!alloc_page_type(page, type)) ) - { - MEM_LOG("Error while validating mfn %lx (pfn %lx) for type %08x" - ": caf=%08x taf=%" PRtype_info, - page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)), - type, page->count_info, page->u.inuse.type_info); - /* Noone else can get a reference. We hold the only ref. */ - page->u.inuse.type_info = 0; - return 0; - } - - /* Noone else is updating simultaneously. */ - __set_bit(_PGT_validated, &page->u.inuse.type_info); - } - - return 1; -} diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index dc09f2a3e6..8f32c6da6d 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -14,6 +14,9 @@ extern void domain_relinquish_resources(struct domain *); +/* given a current domain metaphysical address, return the physical address */ +extern unsigned long translate_domain_mpaddr(unsigned long mpaddr); + /* Flush cache of domain d. If sync_only is true, only synchronize I&D caches, if false, flush and invalidate caches. */ -- 2.30.2